import sys
import os
import S3DPath
from PyQt4 import QtCore
from PyQt4.QtGui import *
from PyQt4.QtCore import SIGNAL, QCoreApplication, Qt
from S3D.Util import Workspace

qApp = QApplication(sys.argv)

EMPTY_ICON = QPixmap(32, 32)
EMPTY_ICON.fill(QColor(0, 0, 0, 0))
EMPTY_ICON = QIcon(EMPTY_ICON)

COMMON_ICON_PATH    = os.path.join(S3DPath.path, r"S3D\Tools\Icons\Common")
WORKSPACE_ICON_PATH = os.path.join(S3DPath.path, r"S3D\Tools\Icons\Workspace")

def loadIcon(path):
    _, ext = os.path.splitext(path)
    if not ext:
        path += '.ico'

    return QIcon(os.path.join(S3DPath.path, r"S3D\Tools\Icons", path))

def loadCommonIcon(*name):
    return loadIcon(os.path.join("Common", *name))

def loadWorkspaceIcon(workspaceName):
    path = workspaceName
    _, ext = os.path.splitext(workspaceName) # make sure it has no '.ico' at the end
    if not ext:
        path += ".ico"

    path = os.path.join(WORKSPACE_ICON_PATH, path)
    if os.path.exists(path):
        return QIcon(path)
    return EMPTY_ICON

def ensureSingleApp(name):
    global mem

    mem = QtCore.QSharedMemory("%s Shared Memory" % name)
    if not mem.create(64) and mem.error() == QtCore.QSharedMemory.AlreadyExists:
        print("%s is already running." % name)
        sys.exit(0)

def getValue(parent, title, message, type=str):
    dlg     = QDialog(parent)
    layout  = QGridLayout()

    dlg.setWindowTitle(title)

    # message
    layout.addWidget(QLabel(message), 0, 0)

    # value
    value = QLineEdit()
    layout.addWidget(value, 0, 1)

    # buttons
    btnBox = QDialogButtonBox()
    btnBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok)

    def onAccept():
        try:
            type(value.text())
            dlg.accept()
        except:
            pass

    dlg.connect(btnBox, SIGNAL("accepted()"), onAccept)
    dlg.connect(btnBox, SIGNAL("rejected()"), dlg.reject)
    layout.addWidget(btnBox, 1, 1, 1, 2)
    
    dlg.setLayout(layout)

    if QDialog.Accepted != dlg.exec_():
        return None

    try:
        return type(value.text())
    except:
        return None

def translateList(obj, list, key=None):
    tr = obj.tr

    if key is None:
        return [tr(p) for p in list]
    return [tr(key(p)) for p in list]

def translateTupleList(obj, list, index=0, key=None):
    tr = obj.tr

    if key is None:
        return [tr(p[index]) for p in list]
    return [tr(key(*p)) for p in list]

def items(ctrl):
    for index in range(ctrl.count()):
        yield ctrl.item(index)

def treeItems(parent):
    if isinstance(parent, QTreeWidget):
        for index in range(parent.topLevelItemCount()):
            yield parent.topLevelItem(index)
    else:
        for index in range(parent.childCount()):
            yield parent.child(index)

def addTreeItem(parent, *columns):
    item = QTreeWidgetItem(columns)

    if isinstance(parent, QTreeWidget):
        parent.addTopLevelItem(item)
    else:
        parent.addChild(item)

    return item

def initWorkspace(workspaceBox, config, configKey="workspace", onChange=None):
    workspaces = Workspace.getWorkspaceList()

    workspaceBox.addItems(workspaces)
    for index, name in enumerate(workspaces):
        workspaceBox.setItemIcon(index, loadWorkspaceIcon(name))

    try:
        index = workspaces.index(getattr(config, configKey))
    except:
        index = 0

    workspaceBox.setCurrentIndex(index)
    curWorkspace = workspaces[index]
    setattr(config, configKey, curWorkspace)
    Workspace.setWorkspace(curWorkspace)

    def setWorkspace(index):
        workspace = workspaces[index]
        setattr(config, configKey, workspace)
        onChange(workspace)

    QtCore.QObject.connect(workspaceBox, SIGNAL("currentIndexChanged(int)"), setWorkspace)

class DataBind:
    BIND_INDEX      = 0
    BIND_TEXT       = 1
    BIND_CHECK      = 2
    BIND_VALUE      = 3
    BIND_RADIO      = 4

    def __init__(self):
        self.binds = []
        self.ignoreMessages = False

    def _makeBindProc(self, obj, prop, onChanged=None):
        def proc(value):
            if not self.ignoreMessages:
                setattr(obj, prop, value)
                if onChanged: onChanged(value)
        return proc

    def _makeRadioBindProc(self, index, obj, prop, onChanged=None):
        def proc(checked):
            if not checked or self.ignoreMessages:
                return

            setattr(obj, prop, index)
            if onChanged: onChanged(index)

        return proc

    def bindIndex(self, ctrl, obj, prop, onChanged=None):
        rec = self.BIND_INDEX, ctrl, obj, prop
        self.binds.append(rec)

        QtCore.QObject.connect(ctrl, QtCore.SIGNAL("currentIndexChanged(int)"), self._makeBindProc(obj, prop, onChanged))

    def bindText(self, ctrl, obj, prop, onChanged=None):
        rec = self.BIND_TEXT, ctrl, obj, prop
        self.binds.append(rec)

        QtCore.QObject.connect(ctrl, QtCore.SIGNAL("textChanged(QString)"), self._makeBindProc(obj, prop, onChanged))

    def bindCheck(self, ctrl, obj, prop, onChanged=None):
        rec = self.BIND_CHECK, ctrl, obj, prop
        self.binds.append(rec)

        QtCore.QObject.connect(ctrl, QtCore.SIGNAL("toggled(bool)"), self._makeBindProc(obj, prop, onChanged))

    def bindValue(self, ctrl, obj, prop, onChanged=None):
        rec = self.BIND_VALUE, ctrl, obj, prop
        self.binds.append(rec)

        QtCore.QObject.connect(ctrl, QtCore.SIGNAL("valueChanged(double)"), self._makeBindProc(obj, prop, onChanged))

    def bindRadio(self, ctrlList, obj, prop, onChanged=None):
        rec = self.BIND_RADIO, ctrlList, obj, prop
        self.binds.append(rec)

        for index, ctrl in enumerate(ctrlList):
            QtCore.QObject.connect(ctrl, QtCore.SIGNAL("toggled(bool)"), self._makeRadioBindProc(index, obj, prop, onChanged))
        
    def updateValues(self):
        self.ignoreMessages = True
        try:
            for type, ctrl, obj, prop in self.binds:
                if type == self.BIND_INDEX:
                    index = getattr(obj, prop)
                    ctrl.setCurrentIndex(index)
                elif type == self.BIND_TEXT:
                    text = getattr(obj, prop)
                    ctrl.setText(text)
                elif type == self.BIND_CHECK:
                    checked = getattr(obj, prop)
                    ctrl.setCheckState(Qt.Checked if checked else Qt.Unchecked)
                elif type == self.BIND_VALUE:
                    value = getattr(obj, prop)
                    ctrl.setValue(value)
                elif type == self.BIND_RADIO:
                    index = getattr(obj, prop)
                    ctrl[index].setChecked(Qt.Checked)
                else:
                    raise ValueError("Unknown bind type: %d" % type)
        finally:
            self.ignoreMessages = False
